package iterator

import (
	"fmt"
)

type MenuItem struct {
	name        string
	description string
	vegetarian  bool
	price       float32
}

func NewMenuItem(n string, d string, v bool, p float32) *MenuItem {
	r := new(MenuItem)
	r.name = n
	r.description = d
	r.vegetarian = v
	r.price = p

	return r
}

func (i *MenuItem) getName() string {
	return i.name
}

func (i *MenuItem) getDescription() string {
	return i.description
}

func (i *MenuItem) getPrice() float32 {
	return i.price
}

func (i *MenuItem) isVegetarian() bool {
	return i.vegetarian
}

//////////////////////////////////////////////////////////////
type Menu interface {
	createIterator() Iterator
}

type PancakeHouseMenu struct {
	menuItems []*MenuItem
}

func NewPancakeHouseMenu() *PancakeHouseMenu {
	r := new(PancakeHouseMenu)
	r.menuItems = append(r.menuItems, NewMenuItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99))
	r.menuItems = append(r.menuItems, NewMenuItem("Regular Pancake Breakfast", "Pancakes with fired eggs, sausage", false, 2.99))
	r.menuItems = append(r.menuItems, NewMenuItem("Blueberry Pancakes", "Pancakes made with fresh blueberries", true, 3.49))
	r.menuItems = append(r.menuItems, NewMenuItem("Waffles", "Waffles, with your choice of blueberries or strawberries", true, 3.59))

	return r
}

func (i *PancakeHouseMenu) createIterator() Iterator {
	return NewPancakeHouseMenuIterator(i.menuItems)
}

///////////////////////////////////////////////////////////////
type DinerMenu struct {
	menuItems []*MenuItem
}

func NewDinerMenu() *DinerMenu {
	r := new(DinerMenu)
	r.menuItems = append(r.menuItems, NewMenuItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99))
	r.menuItems = append(r.menuItems, NewMenuItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99))
	r.menuItems = append(r.menuItems, NewMenuItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29))
	r.menuItems = append(r.menuItems, NewMenuItem("Hotdog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05))

	return r
}

func (i *DinerMenu) createIterator() Iterator {
	return NewDinerMenuIterator(i.menuItems)
}

//////////////////////////////////////////////////////////////
type Iterator interface {
	hasNext() bool
	next() interface{}
}

type PancakeHouseMenuIterator struct {
	m []*MenuItem
	p int
}

func NewPancakeHouseMenuIterator(m []*MenuItem) *PancakeHouseMenuIterator {
	r := new(PancakeHouseMenuIterator)
	r.m = m
	r.p = 0

	return r
}

func (i *PancakeHouseMenuIterator) hasNext() bool {
	if i.p >= len(i.m) || i.m[i.p] == nil {
		return false
	}

	return true
}

func (i *PancakeHouseMenuIterator) next() interface{} {
	var r interface{}
	r = i.m[i.p]
	i.p++
	return r
}

type DinerMenuIterator struct {
	m []*MenuItem
	p int
}

func NewDinerMenuIterator(m []*MenuItem) *DinerMenuIterator {
	r := new(DinerMenuIterator)
	r.m = m
	r.p = 0

	return r
}

func (i *DinerMenuIterator) hasNext() bool {
	if i.p >= len(i.m) || i.m[i.p] == nil {
		return false
	}

	return true
}

func (i *DinerMenuIterator) next() interface{} {
	var r interface{}
	r = i.m[i.p]
	i.p++

	return r
}

//////////////////////////////////////////////////////////////
type Waitress struct {
	p Menu
	d Menu
}

func NewWaitress(p Menu, d Menu) *Waitress {
	r := new(Waitress)
	r.p = p
	r.d = d

	return r
}

func (i *Waitress) PrintMenu() {
	it := i.p.createIterator()
	fmt.Println("MENU\n----\nBREAKFAST")
	i.printMenu(it)
	it = i.d.createIterator()
	fmt.Println("\nLUNCH")
	i.printMenu(it)
}

func (i *Waitress) printMenu(it Iterator) {
	for it.hasNext() {
		a := it.next()
		t := a.(*MenuItem)

		fmt.Print(t.getName(), ",")
		fmt.Print(t.getPrice(), "--")
		fmt.Println(t.getDescription())
	}
}
